package com.ulic.customerManApplication.util.file;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.ulic.customerManApplication.util.config.ConfigInfo;
public class FileUploadInterceptor extends AbstractInterceptor {
	private static final long serialVersionUID = -4764627478894962478L;
	protected static final Logger LOG = LoggerFactory
			.getLogger(FileUploadInterceptor.class);
	protected boolean useActionMessageBundle;
	protected Long maximumSize;
	protected Set<String> allowedTypesSet;
	protected Set<String> allowedExtensionsSet;
	protected String message;
	ConfigInfo configInfo = new ConfigInfo();

	public FileUploadInterceptor() {
		this.allowedTypesSet = Collections.emptySet();
		this.allowedExtensionsSet = Collections.emptySet();
		message = "";
	}
	public void setUseActionMessageBundle(String value) {
		this.useActionMessageBundle = Boolean.valueOf(value).booleanValue();
	}

	public void setAllowedExtensions(String allowedExtensions) {
		this.allowedExtensionsSet = TextParseUtil
				.commaDelimitedStringToSet(allowedExtensions);
	}

	public void setAllowedTypes(String allowedTypes) {
		this.allowedTypesSet = TextParseUtil
				.commaDelimitedStringToSet(allowedTypes);
	}

	public void setMaximumSize(Long maximumSize) {
		this.maximumSize = maximumSize;
	}

	public String intercept(ActionInvocation invocation) throws Exception {
		boolean pass = true;
		ActionContext ac = invocation.getInvocationContext();

		HttpServletRequest request = (HttpServletRequest) ac
				.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");

		if (!(request instanceof MultiPartRequestWrapper)) {
			if (LOG.isDebugEnabled()) {
				ActionProxy proxy = invocation.getProxy();
				LOG.debug(
						getTextMessage(
								"struts.messages.bypass.request",
								new Object[]{proxy.getNamespace(),
										proxy.getActionName()}, ac.getLocale()),
						new String[0]);
			}

			return invocation.invoke();
		}

		ValidationAware validation = null;

		Object action = invocation.getAction();

		if (action instanceof ValidationAware) {
			validation = (ValidationAware) action;
		}

		MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;

		if (multiWrapper.hasErrors()) {
			for (String error : multiWrapper.getErrors()) {
				if (validation != null) {
					validation.addActionError(error);
				}

				LOG.error(error, new String[0]);
			}

		}

		Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
		while ((fileParameterNames != null)
				&& (fileParameterNames.hasMoreElements())) {
			String inputName = (String) fileParameterNames.nextElement();

			String[] contentType = multiWrapper.getContentTypes(inputName);

			if (isNonEmpty(contentType)) {
				String[] fileName = multiWrapper.getFileNames(inputName);

				if (isNonEmpty(fileName)) {
					File[] files = multiWrapper.getFiles(inputName);
					if ((files != null) && (files.length > 0)) {
						List acceptedFiles = new ArrayList(files.length);
						List acceptedContentTypes = new ArrayList(files.length);
						List acceptedFileNames = new ArrayList(files.length);
						String contentTypeName = inputName + "ContentType";
						String fileNameName = inputName + "FileName";

						for (int index = 0; index < files.length; ++index) {
							if (acceptFile(action, files[index],
									fileName[index], contentType[index],
									inputName, validation, ac.getLocale())) {
								acceptedFiles.add(files[index]);
								acceptedContentTypes.add(contentType[index]);
								acceptedFileNames.add(fileName[index]);
							} else {
								request.setAttribute("message", request.getAttribute("message") != null?request.getAttribute("message"):"" + message);
							}
						}

						if (!acceptedFiles.isEmpty()) {
							Map params = ac.getParameters();

							params.put(inputName, acceptedFiles
									.toArray(new File[acceptedFiles.size()]));
							params.put(contentTypeName, acceptedContentTypes
									.toArray(new String[acceptedContentTypes
											.size()]));
							params.put(fileNameName, acceptedFileNames
									.toArray(new String[acceptedFileNames
											.size()]));
						}
						
						if(acceptedFiles.isEmpty()) {
							pass = false;
						}
					}
				} else {
					LOG.error(
							getTextMessage(action,
									"struts.messages.invalid.file",
									new Object[]{inputName}, ac.getLocale()),
							new String[0]);
				}
			} else {
				LOG.error(
						getTextMessage(action,
								"struts.messages.invalid.content.type",
								new Object[]{inputName}, ac.getLocale()),
						new String[0]);
			}

		}

		String result = invocation.invoke();

		fileParameterNames = multiWrapper.getFileParameterNames();
		while ((fileParameterNames != null)
				&& (fileParameterNames.hasMoreElements())) {
			String inputValue = (String) fileParameterNames.nextElement();
			File[] files = multiWrapper.getFiles(inputValue);

			for (File currentFile : files) {
				if (LOG.isInfoEnabled()) {
					LOG.info(
							getTextMessage(action,
									"struts.messages.removing.file",
									new Object[]{inputValue, currentFile},
									ac.getLocale()), new String[0]);
				}

				if ((currentFile != null) && (currentFile.isFile())) {
					currentFile.delete();
				}
				pass = false;
			}
		}
		if(pass) {
			return result;
		} else {
			return "/jsp/document/error.jsp";
		}
	}

	protected boolean acceptFile(Object action, File file, String filename,
			String contentType, String inputName, ValidationAware validation,
			Locale locale) {
		message = "";
		boolean fileIsAcceptable = false;

		if (file == null) {
			String errMsg = getTextMessage(action,
					"struts.messages.error.uploading", new Object[]{inputName},
					locale);
			if (validation != null) {
				validation.addFieldError(inputName, errMsg);
			}

			LOG.error(errMsg, new String[0]);
		} else if ((this.maximumSize != null)
				&& (this.maximumSize.longValue() < file.length())) {
			String errMsg = getTextMessage(
					action,
					"struts.messages.error.file.too.large",
					new Object[]{inputName, filename, file.getName(),
							"" + file.length()}, locale);
			if (validation != null) {
				validation.addFieldError(inputName, errMsg);
				message = "附件\"" + filename + "\"超过了设定的文件大小限制，当前设定最大允许" + configInfo.getPropertiesValue("fileSize") + "的附件。";
			}

			LOG.error(errMsg, new String[0]);
		} else if ((!this.allowedTypesSet.isEmpty())
				&& (!containsItem(this.allowedTypesSet, contentType))) {
			String errMsg = getTextMessage(action,
					"struts.messages.error.content.type.not.allowed",
					new Object[]{inputName, filename, file.getName(),
							contentType}, locale);
			if (validation != null) {
				validation.addFieldError(inputName, errMsg);
				message = "不允许附件\"" + filename + "\"的文件格式，当前设定允许的文件格式为" + configInfo.getPropertiesValue("fileType") + "。";
			}

			LOG.error(errMsg, new String[0]);
		} else if ((!this.allowedExtensionsSet.isEmpty())
				&& (!hasAllowedExtension(this.allowedExtensionsSet, filename))) {
			String errMsg = getTextMessage(action,
					"struts.messages.error.file.extension.not.allowed",
					new Object[]{inputName, filename, file.getName(),
							contentType}, locale);
			if (validation != null) {
				validation.addFieldError(inputName, errMsg);
				message = "不允许附件\"" + filename + "\"的文件格式，当前设定允许的文件格式为" + configInfo.getPropertiesValue("fileType") + "。";
			}

			LOG.error(errMsg, new String[0]);
		} else {
			fileIsAcceptable = true;
		}

		return fileIsAcceptable;
	}

	private static boolean hasAllowedExtension(
			Collection<String> extensionCollection, String filename) {
		if (filename == null) {
			return false;
		}

		String lowercaseFilename = filename.toLowerCase();
		for (String extension : extensionCollection) {
			if (lowercaseFilename.endsWith(extension)) {
				return true;
			}
		}

		return false;
	}

	private static boolean containsItem(Collection<String> itemCollection,
			String item) {
		return itemCollection.contains(item.toLowerCase());
	}

	private static boolean isNonEmpty(Object[] objArray) {
		boolean result = false;
		for (int index = 0; (index < objArray.length) && (!result); ++index) {
			if (objArray[index] != null) {
				result = true;
			}
		}
		return result;
	}

	private String getTextMessage(String messageKey, Object[] args,
			Locale locale) {
		return getTextMessage(null, messageKey, args, locale);
	}

	private String getTextMessage(Object action, String messageKey,
			Object[] args, Locale locale) {
		if ((args == null) || (args.length == 0)) {
			if ((action != null) && (this.useActionMessageBundle)) {
				return LocalizedTextUtil.findText(action.getClass(),
						messageKey, locale);
			}
			return LocalizedTextUtil.findText(super.getClass(), messageKey,
					locale);
		}
		if ((action != null) && (this.useActionMessageBundle)) {
			return LocalizedTextUtil.findText(action.getClass(), messageKey,
					locale, "no.message.found", args);
		}
		return LocalizedTextUtil.findText(super.getClass(), messageKey, locale,
				"no.message.found", args);
	}
}